#include "SQLiteManager.h"
#include "LogEx.h"
#include "StackTrace.h"
using namespace std;
using namespace SGLib;

CSQLiteManager::CSQLiteManager()
{
    m_worker = NULL;
    m_isStop = true;
    m_db = NULL;
    m_curdbfile = "";
}

CSQLiteManager::~CSQLiteManager()
{
    if( m_db )
    {
        sqlite3_close( m_db );
        m_db = NULL;
        m_curdbfile = "";
    }
}

bool CSQLiteManager::Start()
{
    if( m_worker )
    {
        return true;
    }

    m_isStop = false;
    m_worker = new CThread( this );
    if( m_worker == NULL || !m_worker->Start() )
    {
        SAFE_DELETE( m_worker );
        return false;
    }
    
    LOG_INFO( "CSQLiteManager Start" );

    return true;
}

void CSQLiteManager::Stop()
{
    if( !m_isStop && m_worker )
    {
        m_isStop = true;
        m_workSignal.SetEvent();
        m_worker->Stop();
        SAFE_DELETE( m_worker );
    }
    LOG_INFO( "CSQLiteManager Stop" );
}

void CSQLiteManager::Run()
{
    LOG_INFO( "CSQLiteManager Run" );
    while( !m_isStop )
    {
        m_workSignal.Wait();

        if( m_isStop )
        {
            break;
        }

        while( 1 )
        {
            sqlReq _req;
            {
                CGuardLock<CLock> g(m_lock);
                if( m_reqQue.empty() )
                {
                    break;
                }
                _req = m_reqQue.front();
                m_reqQue.pop_front();
            }
            _DoExec( _req );
        }
    }
    LOG_INFO( "CSQLiteManager Run End" );
}

void CSQLiteManager::Exec(const char *dbfile, const char *sql, std::string &userdata, OnExecDone onExecDone)
{
    sqlReq req;
    req.dbfile = dbfile;
    req.sql = sql;
    req.userdata = userdata;
    req.onExecDone = onExecDone;
    _DoAddRequest( req );
}

void CSQLiteManager::ExecSelect(const char *dbfile, const char *sql, std::string &userdata, OnSelect onSelect)
{
    sqlReq req;
    req.sqltype = 1;
    req.dbfile = dbfile;
    req.sql = sql;
    req.userdata = userdata;
    req.onSelect = onSelect;
    _DoAddRequest( req );
}

void CSQLiteManager::ExecSync(const char *dbfile, const char *sql, OnSelect onSelect)
{
    sqlReq req;
    req.sqltype = 1;
    req.dbfile = dbfile;
    req.sql = sql;
    req.onSelect = onSelect;
    _DoExec( req );
}

void CSQLiteManager::_DoAddRequest(sqlReq &req)
{
    {
        CGuardLock<CLock> g(m_lock);
        m_reqQue.push_back( req );
    }
    m_workSignal.SetEvent();
}

void CSQLiteManager::_DoExec(sqlReq &req)
{
    if( req.dbfile != m_curdbfile )
    {
        LOG_INFO( "CSQLiteManager [%s][%s][%d] DBFile changed. old[%s] new[%s]",
            __FILE__, __FUNCTION__, __LINE__, m_curdbfile.c_str(), req.dbfile.c_str() );
        if( m_db )
        {
            sqlite3_close( m_db );
            m_db = NULL;
        }
        m_curdbfile = req.dbfile;
        int ret = sqlite3_open( m_curdbfile.c_str(), &m_db );
        if( ret != SQLITE_OK ) 
        {
            LOG_ERROR( "CSQLiteManager [%s][%s][%d] sqlite3_open [%s] failed. ret[%d]",
                __FILE__, __FUNCTION__, __LINE__, m_curdbfile.c_str(), ret );
            return;
        }
    }
    
    char *errmsg = NULL;
    int ret = sqlite3_exec( m_db, req.sql.c_str(), req.onSelect, 0, &errmsg );  
    if( ret != SQLITE_OK )
    {
        LOG_ERROR( "CSQLiteManager [%s][%s][%d] sqlite3_exec [%s] failed. ret[%d]",
                __FILE__, __FUNCTION__, __LINE__, req.sql.c_str(), ret );
        return;
    }
    
    if( req.onExecDone )
    {
        req.onExecDone( req.userdata );
    }
}



